var masterData = [];
var intervalData = [];
var breakpointData = [];
var scheduleTypes = {};
var workspaces = {};
var selected = new SelectedContainer();
var scheduleChart;
var sequence = 0;
var valueTypeByScheduleType;
var valueTypes;
var dateHours = [];

var revision = 0;
var DAY_FORMAT = "yyyy-MM-dd";
var DATE_FORMAT = "yyyy-MM-dd HH:mm";


var masterColumns = [
    {id:"start", field:"start", name:i18n.schedule.grid.startDate, width:100, sortable: true},
    {id:"stop", field:"stop", name:i18n.schedule.grid.stopDate, width:100, sortable: true},
    {id:"status", field:"status", name:i18n.schedule.grid.status, width:100, cssClass:"cell-title", sortable: true},
    {id:"identification", field:"identification", name:i18n.schedule.grid.scheduleId, width:120, cssClass:"cell-title", sortable: true},
    {id:"documentIdentification", field:"documentIdentification", name:i18n.schedule.grid.documentId, width:120, cssClass:"cell-title", sortable: true},
    {id:"workspaceDesc", field:"workspaceDesc", name:i18n.schedule.grid.workspace, width:150, cssClass:"cell-title", sortable: true},
    {id:"typeDesc", field:"typeDesc", name:i18n.schedule.grid.type, width:150, cssClass:"cell-title", sortable: true},
    {id:"selection", field:"selection", name: i18n.schedule.grid.selection, width:100, cssClass:"cell-effort-driven", formatter: CheckboxCellFormatter}
];

var detailColumns = [
    {id:"start", field:"start", name:i18n.schedule.grid.startDate, width:100, unselectable: true, cssClass:"time-column", priority: 1},
    {id:"schedule", field:"schedule", name:i18n.schedule.grid.scheduleId, width:120, unselectable: true, priority: 2},
    {id:"workspaceDesc", field:"workspaceDesc", name:i18n.schedule.grid.workspace, width:150, unselectable: true, priority: 3},
    {id:"type", field:"type", name:i18n.schedule.grid.type, width:150, unselectable: true, priority: 4},
    {id:"uomDesc", field:"uomDesc", name:i18n.schedule.grid.uom, width:50, unselectable: true, priority: 5}
];

var intervalSumColumns = [
    {id:"sum", field:"sum", name:i18n.schedule.grid.sum, width:50, unselectable: true, cssClass:"time-column"},
    {id:"sum2", field:"sum", name:i18n.schedule.grid.sum, width:50, unselectable: true, cssClass:"time-column", priority: 9}
];

var typeColumns = {};
var intervalColumns = [];
var breakpointColumns = [];

var masterOptions = {
    editable: false,
    sortable: true,
    enableAddRow: false,
    enableCellNavigation: false,
    syncColumnCellResize: true,
    rowCssClasses: function(item) {
        return item.selection.checked ? 'complete' : '';
    },

    showColumnPicker: true,
    showPager: false,
    onFilter: masterFilter,
    onSort: masterSort,
    onClick: onGridClick,
    onCellPaste: null
};

var detailOptions = {
    editable: true,
    sortable: false,
    enableColumnReorder : false,
    syncColumnCellResize: true,
    enableAddRow: false,

    enableCellNavigation: true,
    showColumnPicker: true,
    showPager: false,
    onSort: null,
    onClick: null,
    onCellPaste: onPaste,
    onBeforeEditCell: null,
    onCellChange: onCellChange
};

var intervalOptions = $.extend({}, detailOptions, {onFilter: intervalFilter});
var breakpointOptions = $.extend({}, detailOptions);

var masterGrid = new DataGrid(masterColumns, masterOptions);
var intervalGrid = new DataGrid(intervalColumns.concat(detailColumns).concat(intervalSumColumns), intervalOptions);
var breakpointGrid = new DataGrid(breakpointColumns.concat(detailColumns), breakpointOptions);

var REFR_BUTTON_STATES_EVENT = "REFR_BUTTON_STATES_EVENT";

$(function() {
    masterGrid.attachTo($("#masterGrid"));
    intervalGrid.attachTo($("#intervalGrid"));
    breakpointGrid.attachTo($("#breakpointGrid"));

    $(".static").change(refreshData);

    $(window).resize(resizeTables);

    addDateValidation($("#day"));

    $("#fixed-panel label.panel-header").collapsiblePanel({
                minimize: function() {
                    $(this).hide();
                    resizeTables();
                },
                restore: function() {
                    $(this).show();
                    resizeTables();
                }
            });
    $("#flexible-panel label.panel-header").collapsiblePanel({
                minimize:function() {
                    $(".panel > .panel-header, .panel > .panel-content").removeClass("invisible");
                    $(this).hide();
                    resizeTables();
                },
                restore:function() {
                    $(".panel > .panel-header, .panel > .panel-content").removeClass("invisible");
                    $(this).show();
                    resizeTables();
                },
                maximize:function(header) {
                    $(".panel > .panel-header, .panel > .panel-content").addClass("invisible");
                    $(header).removeClass("invisible");
                    $(this).removeClass("invisible");
                    resizeTables();
                }
            });

    $("#excelExport").click(excelExport);
    $("#rampExport").click(rampExport);
    $("#addSchedule").click(newScheduleClick);

    $("#deleteSchedules").click(deleteAll);
    $("#saveSchedules").click(saveAll);
    $("#cancelSchedules").click(cancelAll);

    $("#selectAll").click(selectAll);
    $("#deselectAll").click(deselectAll);

    $("#duplicate").click(duplicate);

    $("#addPoint").button("enable");
    $("#addPoint").click(addPoint).hide();
    $("#addPointTime").change(
            function() {
                $("#addPointError").hide();
            }).change();

    $("#zoomControlPanel").buttonset().hide();

    $("#day").val($.namesession.get("scheduleDay", $("#day").val()));
    $("#day").change(function() {
        $.namesession.set("scheduleDay", $("#day").val());
    });

    $("#targetDay").change(function() {
        if (isDateValid($("#targetDay"))) {
            $("#duplicateDialogError").hide();
        } else {
            $("#duplicateDialogError").show();
        }
    });

    var $tabs = $("#tabs-panel").tabs();

    $tabs.bind("tabsshow",
            function (e, ui) {
                switch (ui.panel.id) {
                    case "interval-tab" :
                        intervalGrid.commit();
                        breakpointGrid.commit();
                        $("#addPoint").hide();
                        $("#zoomControlPanel").hide();
                        intervalGrid.refresh();
                        return;
                    case "breakpoint-tab" :
                        intervalGrid.commit();
                        breakpointGrid.commit();
                        $("#addPoint").show();
                        $("#zoomControlPanel").hide();
                        breakpointGrid.refresh();
                        return;
                    case "chart-tab" :
                        $(".jqplot-error-message").remove();
                        intervalGrid.commit();
                        breakpointGrid.commit();
                        $("#addPoint").hide();
                        $("#zoomControlPanel").show();
                        scheduleChart.draw();
                        scheduleChart.repaint();
                        return;
                }
            }).tabs("select", $tabs.tabs("option", "selected"));

    selected.subscribe(SelectedContainer.PUT_NEW, displayDetails);
    selected.subscribe(SelectedContainer.CLEAR_ALL, displayDetails);
    selected.subscribe(SelectedContainer.PUT_EXISTED, displayDetails);
    selected.subscribe(SelectedContainer.REMOVE_EXISTED, displayDetails);

    selected.subscribe(SelectedContainer.CLEAR_ALL, refreshGrids);
    selected.subscribe(SelectedContainer.ROLLBACK_ALL, refreshGrids);
    selected.subscribe(SelectedContainer.PUT_NEW, refreshGrids);
    selected.subscribe(SelectedContainer.PUT_EXISTED, refreshGrids);

    selected.subscribe(SelectedContainer.CLEAR_ALL, processColumns);
    selected.subscribe(SelectedContainer.REMOVE_EXISTED, processColumns);
    selected.subscribe(SelectedContainer.PUT_NEW, processColumns);

    selected.subscribe(SelectedContainer.PUT_NEW, changeButtonsState);
    selected.subscribe(SelectedContainer.CLEAR_ALL, changeButtonsState);
    selected.subscribe(SelectedContainer.PUT_EXISTED, changeButtonsState);
    selected.subscribe(SelectedContainer.ROLLBACK_ALL, changeButtonsState);
    selected.subscribe(SelectedContainer.REMOVE_EXISTED, changeButtonsState);

    selected.subscribe(SelectedContainer.MODIFY_VALUE, changeButtonsState);

    subscribeToRefreshButtonStates();

    $("#scheduleType option").each(function() {
        var $this = $(this);

        scheduleTypes[$this.val()] = {
            name: $this.text(),
            resolution: convertDuration($this.attr("resolution")),
            breakpoint: $this.attr("breakpoint") == "true",
            editable : $this.attr("editable") == "true"
        };
    });

    $("#workspace option").each(function() {
        var $this = $(this);

        workspaces[$this.val()] = {
            name: $this.text()
        };
    });

    // Validate during user input
    $("#addScheduleDialog input").bind("keyup change", function() {
        if (isIdentificationEmpty()) {
            $("#emptyIdentificationError").show();
            return;
        } else {
            $("#emptyIdentificationError").hide();
        }

        if (!validFormInput()) {
            $("#addScheduleDialogError").show();
        } else {
            $("#addScheduleDialogError").hide();
        }
    });

    refreshData(null);
    displayDetails();
    resizeTables();

    setInterval(function() {
        if (!isDateValid($("#day"))) {
            return;
        }

        var workspace = selectedWorkspaceCode();
        var type = selectedType();
        var date = parseDate($("#day").val());

        dwr.engine.beginBatch();

        try {
            dwr.engine._batch.preHooks = [];
            dwr.engine._batch.postHooks = [];

            ScheduleServiceRemote.hasNew(workspace, type, date, revision, {callback: function(answer) {
                        if (answer) {
                            var specificCase = typeof outageScheduleType !== 'undefined' && type === outageScheduleType;

                            if (!specificCase) {
                                refreshData(null);
                            }

                            if (!selected.isEmpty()) {
                                if (specificCase) {
                                    var masterFilterModels = {};
                                    var extraModels = {};

                                    selected.iterate(function() {
                                        if (this.model.getType() === outageScheduleType) {
                                            var ident = this.schedule().identification;

                                            if (masterFilterWithoutParameters(this)) {
                                                masterFilterModels[ident] = this.model;
                                            } else {
                                                extraModels[ident] = this.model;
                                            }

                                            selected.remove(this.model);
                                        }
                                    });

                                    refreshData(null);

                                    showAlertDialog($("#refreshOutageSchedulesDialog"), function() {
                                        processOutages(masterFilterModels, extraModels);

                                        $(this).dialog("close");
                                    }, 450, 170);
                                } else {
                                    refreshDialog();
                                }
                            }
                        }
                    }});
        } finally {
            dwr.engine.endBatch();
        }
    }, 10000);
});

function refreshDialog() {
    showConfirmDialog($("#refreshSchedulesDialog"), function() {
        selected.rollbackAll();

        $(this).dialog("close");
    }, null, true);
}

function resizeTables() {
    var $detail = $("#tabs-panel");
    var $panels = $("#flexible-panel > .panel-content");
    var $visiblePanels = $panels.filter(":visible");

    var panelCount = $panels.length;
    var visiblePanelCount = $visiblePanels.length;

    var panelHeaderHeight = $(".panel-header:visible").outerHeight(true);
    var fullHeight = $("#pageContent").innerHeight() - $("#fixed-panel").outerHeight(true);
    var panelHeight = visiblePanelCount === 0 ? 0 : (fullHeight - panelCount * panelHeaderHeight) / visiblePanelCount;

    $("#flexible-panel").height(fullHeight);

    $visiblePanels.height(panelHeight);

    var detailHeight = $detail.height();
    var detailHeaderHeight = $("#tabs-header").outerHeight(true);

    $("#tabs-content").height(detailHeight - detailHeaderHeight - 10);

    refreshGrids();
    scheduleChart && scheduleChart.repaint();
}

function subscribeToRefreshButtonStates() {
    $("body").bind(REFR_BUTTON_STATES_EVENT, function() {
        changeButtonsState();
    })
}

function fireRefreshButtonStates() {
    $("body").trigger(jQuery.Event(REFR_BUTTON_STATES_EVENT));
}

function refreshGrids() {
    masterGrid.refresh();
    intervalGrid.refresh();
    breakpointGrid.refresh();
}

function changeButtonsState() {
    function hasEditableSchedules() {
        var arr = selected.list();
        for (var i = 0; i < arr.length; i++) {
            if (canEditSchedule(arr[i].schedule())) {
                return true;
            }
        }
        return false;
    }

    function states(aNew, save, cancel, aDelete, selectAll, deselectAll, duplicate, excel) {
        function _(p, id) {
            var $button = $("#" + id);

            $button.removeClass('ui-state-focus');
            $button.removeClass('ui-state-hover');
            $button.button(p ? "enable" : "disable");
        }

        _(aNew, "addSchedule");
        _(save, "saveSchedules");
        _(cancel, "cancelSchedules");
        _(aDelete, "deleteSchedules");
        _(selectAll, "selectAll");
        _(deselectAll, "deselectAll");
        _(duplicate, "duplicate");
        _(excel, "excelExport");
        _(excel, "rampExport");
    }


    var masterWs = $("#workspace option:selected").attr("masterWorkspace");
    var editable = selectedScheduleType().editable;
    var selEmpty = selected.isEmpty();
    var selAll = gotTheShownSchedules();
    var modified = selected.hasModified();
    var aDelete = hasEditableSchedules();

    if (masterWs && !editable) {
        states(false, false, false, aDelete, selAll, !selEmpty, true, !selEmpty);
    } else {
        states(true, modified, modified, aDelete, selAll, !selEmpty, true, !selEmpty);
    }
}

function displayDetails() {
    var hasBreakpoint = false;

    selected.iterate(function() {
        return !(hasBreakpoint = this.isBreakpoint());
    });

    if (hasBreakpoint) {
        $("#breakpoint-tab").show();
        $("li a[href='#breakpoint-tab']").parent().show();
    } else {
        if ($("#tabs-panel").tabs("option", "selected") === 1) {
            $("#tabs-panel").tabs("select", 0);
        }

        $("#breakpoint-tab").hide();
        $("li a[href='#breakpoint-tab']").parent().hide();
    }
}

function refreshData(e) {
    if (!isDateValid($("#day"))) {
        $("#day").addClass("error");
        return;
    }

    var workspace = selectedWorkspaceCode();
    var type = selectedType();
    var date = parseDate($("#day").val());

    dwr.engine.beginBatch();

    try {
        if (!valueTypeByScheduleType || !valueTypes) {
            ScheduleServiceRemote.getAllValueTypes({callback: processValueTypes});
        }

        if (!e || e.target.id === "scheduleType" || e.target.id == "day") {
            ScheduleServiceRemote.getScheduleParamList(type, date, {callback: processParameters});
        }

        if (!e || e.target.id == "day") {
            ScheduleServiceRemote.getDateHours(date, {callback: function(hours) {
                        dateHours = hours;
                    }});
        }

        ScheduleServiceRemote.getScheduleList(workspace, type, date, {callback: processSchedules});
    } finally {
        dwr.engine.endBatch();
    }
}

function selectAll() {
    var models = new Array();
    $.each(masterData, function(key, val) {
        if (val.selection.checked || !masterFilter(this)) {
            return true;
        }

        models.push(this.model);
    });

    selected.putAll(models);

    processBreakpoints();
    refreshGrids();
}

function deselectAll() {
    selected.hasModified() && showConfirmDialog($("#uncheckAllSchedulesDialog"), function() {
        selected.clearAll();

        $(this).dialog("close");
    }, null, false);

    !selected.hasModified() && selected.clearAll();
}

function cancelAll() {
    intervalGrid.refresh();
    breakpointGrid.refresh();

    selected.hasModified() && showConfirmDialog($("#cancelSchedulesDialog"), function() {
        selected.rollbackAll();

        var len = masterData.length;

        for (var i = 0; i < len; i++) {
            if (masterData[i].isNew()) {
                masterData.splice(i, 1);
                i--;
                len--;
            }
        }

        refreshGrids();

        $(this).dialog("close");
    }, null, false);
}

function saveAll() {
    intervalGrid.refresh();
    breakpointGrid.refresh();

    var schedules = selected.list(function(item) {
        if (item.isModified()) {
            return item.toJavaBean();
        }
    });

    schedules.length > 0 && showConfirmDialog($("#saveSchedulesDialog"), function() {
        $(this).dialog("close");

        submitChanges(schedules);
    }, null, false);
}

function deleteAll() {
    intervalGrid.refresh();
    breakpointGrid.refresh();

    var schedules = selected.list(function(item) {
        item = item.toJavaBean();

        item.deleted = true;

        return item;
    });

    schedules.length > 0 && showConfirmDialog($("#deleteSchedulesDialog"), function() {
        $(this).dialog("close");

        selected.clearAll();

        submitChanges(schedules);
    }, null, false);
}

function duplicate() {
    $("#duplicateDialogError").hide();

    if (selected.isEmpty()) {
        $("#duplicateSelected").attr('disabled', 'true');
    }

    if (!gotTheShownSchedules() || !selectedScheduleType().editable) {
        $("#duplicateFiltered").attr('disabled', 'true');
    }

    showConfirmDialog($("#duplicateDialog"), function() {
        if (!validTargetDay()) {
            return;
        }

        var mode = $('input:radio[name=duplicateFilter]:checked').val();

        switch (mode) {
            case "0":
                duplicateSelected();
                return;
            case "1":
                duplicateFiltered();
                return;
            case "2":
                duplicateAll();
        }

    }, null, true, function() {
        $("#duplicateDialogError").hide();
        $("#duplicateAll").attr('checked', 'checked');
        $("#duplicateSelected").removeAttr('disabled');
        $("#duplicateSelected").removeAttr('checked');
        $("#duplicateFiltered").removeAttr('disabled');
        $("#duplicateFiltered").removeAttr('checked');
    });
}

function duplicateSelected() {
    if (selected.hasModified()) {
        showAlertDialog($("#duplicateWarningDialog"), null, 400, 150);
        return;
    }

    if (selected.hasNonEditable()) {
        showAlertDialog($("#duplicateNonEditableDialog"), null, 400, 150);
        return;
    }

    var ids = new Array();
    var workspaceList = new Array();

    selected.list(function(item) {
        workspaceList[workspaceList.length] = item.workspace != null ? item.workspace : "master";

        return ids[ids.length] = item.key();
    });

    var filterDate = parseDate($("#day").val());
    var targetDay = parseDate($("#targetDay").val());

    ScheduleServiceRemote.duplicateSchedules(filterDate, targetDay, ids, workspaceList, {callback: function(result) {
                if (result) {
                    successDuplication($("#targetDay").val())
                } else {
                    alert("Duplication failed because some of the duplicated schedules already exist or duplication of selected schedules will create two identical schedules on the target day")
                }
            }, timeout: 360000
            }
    );
}

function duplicateFiltered() {
    var workspace = selectedWorkspaceCode();
    var type = selectedType();
    var date = parseDate($("#day").val());
    var targetDayString = $("#targetDay").val();
    var targetDay = parseDate(targetDayString);

    ScheduleServiceRemote.duplicateFilteredSchedules(workspace, type, date, createScheduleFilters(), targetDay, {callback: function(result) {
                if (result) {
                    successDuplication(targetDayString)
                } else {
                    alert("Duplication failed because some of the duplicated schedules already exist on target day")
                }
            }, timeout: 360000
            }
    );
}

function duplicateAll() {
    var workspace = selectedWorkspaceCode();
    var date = parseDate($("#day").val());
    var targetDayString = $("#targetDay").val();
    var targetDay = parseDate(targetDayString);

    ScheduleServiceRemote.duplicateAllSchedules(workspace, date, targetDay, {callback: function(result) {
                if (result) {
                    successDuplication(targetDayString)
                } else {
                    alert("Duplication failed because some of the duplicated schedules already exist on target day")
                }
            }, timeout: 360000
            }
    );
}


function successDuplication(targetDay) {
    $("#duplicateDialog").dialog("close");

    alert("Duplication successfully done");

    $("#day").val(targetDay);
    $.namesession.set("scheduleDay", $("#day").val());

    refreshData(null);
}

function createScheduleFilters() {
    return $(".dyno select").map(
            function() {
                if ($.trim($(this).val()) !== '') {
                    return {parameterType: $(this).attr("code"), entityIdentification: $(this).val()};
                }
            }).get();
}

function validTargetDay() {
    if (isDateValid($("#targetDay"))) {
        $("#duplicateDialogError").hide();
        return true;
    } else {
        $("#duplicateDialogError").show();
        return false;
    }
}

function submitChanges(schedules) {
    dwr.engine.beginBatch();

    try {
        ScheduleServiceRemote.updateScheduleList(schedules, {callback: processSchedules});

        var workspace = selectedWorkspaceCode();
        var type = selectedType();
        var date = $("#day").val();

        ScheduleServiceRemote.getScheduleList(workspace, type, date, {callback: processSchedules});
    } finally {
        dwr.engine.endBatch();
    }
}

function processValueTypes(list) {
    valueTypes = {};
    valueTypeByScheduleType = {};

    $.each(list, function() {
        valueTypes[this.code] = this;

        var types = valueTypeByScheduleType[this.scheduleTypeCode];

        if (!types) {
            types = (valueTypeByScheduleType[this.scheduleTypeCode] = []);
        }

        types[types.length] = this;
    });
}

function processParameters(params) {
    $(".dyno").remove();

    typeColumns = {};

    for (var i = 0; i < params.length; i++) {
        var $div = $("<div class='dyno' id='" + params[i].parameterCode + "'></div>");
        var $filter = $("<select id='dyno" + i + "' code='" + params[i].parameterCode + "' name='parameters[\"" + params[i].parameterCode + "\"]'></select>");
        var $label = $("<label for='dyno" + i + "'>" + params[i].parameterName + "</label>");

        $filter.append("<option title='" + i18n.general.all + "' value=''>" + i18n.general.all + "</option>");

        $("#actions fieldset:first").append($div.append($label).append(" ").append($filter));

        //var event = jQuery.Event("dynoready");
        //$label.trigger(event);

        var entities = params[i].entityBeans;

        masterColumn(typeColumns, params[i].parameterCode, params[i].parameterName);

        $.each(entities, function() {
            $filter.append("<option title='" + this.name + "' value='" + this.identification + "'>" + this.name + "</option>");
        });

        $filter.change(function() {
            masterGrid.refresh();
        });
    }

    processColumns();
    resizeTables();
}

function processSchedules(list) {
    masterData = [];
    intervalData = [];
//    breakpointData = [];

    var intervalCols = createColumns();
    selected.iterate(function() {
        this.processed(false);
    });

    processData(list, intervalCols);

    var extraData = selected.list(function() {
        if (!this.processed()) {
            return this.schedule();
        }
    });

    processData(extraData, intervalCols);

    intervalColumns = $.map(intervalCols, identity);
    intervalColumns = intervalColumns.concat(intervalSumColumns);
    intervalColumns.sort(compareColumns);

    masterGrid.data(masterData);
    intervalGrid.data(intervalData).columns([].concat(detailColumns).concat(intervalColumns));
    breakpointGrid.data(breakpointData).columns([].concat(detailColumns).concat(breakpointColumns));

    fireRefreshButtonStates();
}

function processColumns() {
    var selectedCols = $.extend({}, typeColumns);

    selected.list(function() {
        $.each(this.getParameters(), function() {
            masterColumn(selectedCols, this.type, this.caption);
        });
    });

    var selectedColumnsList = $.map(selectedCols, identity);
    var resolution = getMinResolution();

    if (resolution !== null) {

        var i, j, len = intervalColumns.length;
        for (i = 0; i < intervalColumns.length; i++) {
            for (j = i; j < intervalColumns.length && ((intervalColumns[j].hour * DateTime.MILLIS_PER_HOUR + intervalColumns[j].minute * DateTime.MILLIS_PER_MINUTE) % resolution !== 0); j++) {
            }

            if (j > i) {
                intervalColumns.splice(i, j - i);
            }
        }

        //if (len !== intervalColumns.length) {
        intervalGrid.columns([].concat(detailColumns).concat(selectedColumnsList).concat(intervalColumns.concat(intervalSumColumns).sort(compareColumns)));
        //}
    }

    masterGrid.columns([].concat(masterColumns).concat(selectedColumnsList.sort(compareColumns)));
}

function processData(list, intervalCols) {
    $.each(list, function() {
        var model = selected.find(this);

        model = model && selected.move(model.key(), model.recycle(this).key()) || new ScheduleModel(this, false, dateHours);

        model.calculateSum();

        revision = Math.max(revision, model.getRevision());

        var line = masterData[masterData.length] = model.populateGridData();

        model.line(line).processed(true);

        $.each(model.getParameters(), function() {
            masterColumn(intervalCols, this.type, this.caption);
        });

        if (!model.isBreakpoint()) {
            $.each(model.getValues(), function() {
                intervalData[intervalData.length] = this;
                this.iterate(function() {
                    detailColumn(intervalCols, this.getHour(), this.getMinute(), this.isExtra());
                });
            });
        }
    });
}

function masterColumn(columns, code, label) {
    var id = "parameter_" + code;

    if (columns[id] === undefined) {
        columns[id] = {
            id: id,
            field: id,
            name: label,
            width: 150,
            cssClass: "cell-title",
            sortable: true
        };
    }
}

function detailColumn(columns, hour, minute, extra) {
    var key = ScheduleModel.createCaption(hour, minute, extra);

    if (!columns[key]) {
        columns[key] = {id: key, field: key, name: key, hour: hour, minute: minute, extra: extra, width: 55, cssClass: "cell-data time-column", editor: DecimalCellEditor, formatter: DecimalCellFormatter};
    }

    return key;
}

function createColumns() {
    var resolution = getMinResolution();
    var i, minute, columns = {};

    if (resolution !== null) {
        for (i = 0; i < DateTime.MILLIS_PER_DAY; i += resolution) {
            var hour = Math.floor(i / DateTime.MILLIS_PER_HOUR);

            minute = Math.floor((i - hour * DateTime.MILLIS_PER_HOUR) / DateTime.MILLIS_PER_MINUTE);

            detailColumn(columns, hour, minute, false);
        }

        var s, extraHours = dateHours.length > 24 && dateHours || (s = selected.getWithExtra()) && s.getHours();

        if (extraHours) {
            for (i = 0; i < extraHours.length - 1; i++) {
                if (extraHours[i] === extraHours[i + 1]) {
                    var extraHour = extraHours[i];

                    for (i = 0; i < DateTime.MILLIS_PER_HOUR; i += resolution) {
                        minute = Math.floor(i / DateTime.MILLIS_PER_MINUTE);

                        detailColumn(columns, extraHour, minute, true);
                    }

                    break;
                }
            }
        }
    }

    return columns;
}

function getMinResolution() {
    function _selected(model) {
        return model.getResolution();
    }

    var current = selectedScheduleType().resolution;
    var initial = current === null ? [] : [current];

    return Math.min.apply(Math, initial.concat(selected.list(_selected)));
}

function convertDuration(e) {
    if (e === undefined || e === null) {
        return null;
    }

    switch (String(e)) {
        case "PT1H" :
        case "PT60M" :
            return 60 * DateTime.MILLIS_PER_MINUTE;
        case "PT30M" :
            return 30 * DateTime.MILLIS_PER_MINUTE;
        case "PT15M" :
            return 15 * DateTime.MILLIS_PER_MINUTE;
        default:
            return null;
    }
}

function compareColumns(left, right) {
    function _(item) {
        if (item == null || item === undefined) {
            return null;
        }

        var name = item.name;
        var priority = item.priority;

        if (priority !== undefined) {
            switch (priority) {
                case 9:
                    return "Z" + name;
                default:
                    return "!" + priority + name;
            }
        }

        if (name.indexOf(":") === -1) {
            return "." + item.id;
        }

        return item.name.replace(":", item.name.indexOf("*") === -1 ? "A" : "Z");
    }

    return compare(_(left), _(right));
}

function compare(left, right) {
    return left == null || left === undefined || left < right ? -1 : left == right ? 0 : 1;
}

function masterSort(col, asc) {
    function _check(item) {
        return (item.isSelected() === (asc == 1));
    }

    function _masterSort(left, right) {
        var l = (_check(left) ? "A" : "Z") + left[col.field];
        var r = (_check(right) ? "A" : "Z") + right[col.field];

        return compare(l, r);
    }

    function _detailSort(left, right) {
        var l = (_check(left.parent) ? "A" : "Z") + left.parent[col.field];
        var r = (_check(right.parent) ? "A" : "Z") + right.parent[col.field];

        return compare(l, r);
    }

    masterGrid.dataView.sort(_masterSort, asc);
    intervalGrid.dataView.sort(_detailSort, asc);
    breakpointGrid.dataView.sort(_detailSort, asc);
}

function masterFilter(item) {
    var matches = masterFilterWithoutParameters(item);

    $("#actions fieldset:first").find(".dyno select").each(function () {
        var $this = $(this);
        var code = $this.attr("code");

        if (matches && code) {
            var params = item["parameter_" + code + "_code"];

            if (params === undefined) {
                return (matches = $this.val() === "");
            }

            $.each(params, function() {
                return !(matches = equals($this, String(this)));
            });
        }
    });

    return item["selection"].checked || matches;
}

function masterFilterWithoutParameters(item) {
    function workspaceEqual($elem, text) {
        return $elem.val() === "" && text === null || $elem.val() === text;
    }

    var day = Date.parse($("#day").val(), DAY_FORMAT);
    var startDay = day.getTime();
    var stopDay = day.calendar().plusDays(1).time();
    var start = item.startDate.getTime();
    var stop = item.stopDate.getTime();

    return workspaceEqual($("#workspace"), item["workspace"])
            && equals($("#scheduleType"), item["type"])
            && start < stopDay && stop > startDay;
}

function equals($elem, text) {
    return $elem.val() === "" || $elem.val() === text;
}

function intervalFilter(item) {
    return !item["parent"].breakpoint && item["parent"].selection.checked;
}

function onCellChange(row, cell, dataContext, grid) {
    changeButtonsState();

    calculateSum(dataContext);
}

function calculateSum(dataContext) {
    var schedule = selected.get(dataContext.parent.key());

    var newSum = undefined;

    schedule.iterateValues(dataContext.getType(), function() {
        if (this.value() !== null) {
            if (newSum === undefined) {
                newSum = 0;
            }

            newSum += this.value();
        }
    });

    schedule._sumMap[dataContext.getType()] = newSum;

    var data = schedule.isBreakpoint() ? breakpointData : intervalData;

    $.each(data, function() {
        if (this.id === dataContext.id) {
            this.sum = newSum;

            return false;
        }
    });

    refreshGrids();
}

function onGridClick(e, row, cell, grid, dataView) {
    if (e && e.target.name === "selection") {
        var item = grid.getData()[row];
        var selection = item["selection"];

        if (selection.checked) {
            questionForUncheck(selection, item, grid, dataView, e.target);
        } else {
            doGridClick(selection, item, grid, dataView);
        }
    }

    return false;
}

function processSelection(_checked, item) {
    if (_checked) {
        selected.put(item.model);
    } else {
        selected.remove(item.id);
        processColumns();
    }

    if (item.model.isBreakpoint()) {
        processBreakpoints();
    }

    fireRefreshButtonStates();
}

function processBreakpoints() {
    breakpointData = [];

    var breakpointCols = {};
    detailColumn(breakpointCols, 0, 0, false);
    detailColumn(breakpointCols, DateTime.HOURS_PER_DAY, 0, false);

    breakpointColumns = $.map(breakpointCols,
            function(e) {
                e.breakpoint = true;

                return e;
            }).sort(compareColumns);

    selected.iterate(function() {
        if (!this.isBreakpoint()) {
            return true;
        }

        $.each(this.getValues(), function() {
            breakpointData[breakpointData.length] = this;

            this.iterate(function() {
                var columns = {};
                var colKey = detailColumn(columns, this.getHour(), this.getMinute(), this.isExtra());

                var column = columns[colKey];

                column.breakpoint = true;

                $.each(breakpointColumns, function() {
                    if (this.id === colKey) {
                        colKey = null;
                        return false;
                    }
                });

                if (colKey != null) {
                    breakpointColumns[breakpointColumns.length] = columns[colKey];
                }
            });
        });
    });

    var selectedCols = $.extend({}, typeColumns);

    selected.list(function() {
        if (this.isBreakpoint()) {
            $.each(this.getParameters(), function() {
                masterColumn(selectedCols, this.type, this.caption);
            });
        }
    });

    breakpointColumns = breakpointColumns.concat($.map(selectedCols, identity));
    breakpointColumns.sort(compareColumns);

    breakpointGrid.data(breakpointData).columns([].concat(detailColumns).concat(breakpointColumns));
}

function doGridClick(selection, item) {
    selection.checked = !selection.checked;

    processSelection(selection.checked, item);

    masterGrid.sort();

    intervalGrid.refresh();
    breakpointGrid.refresh();
}

function questionForUncheck(selection, item, grid, dataView, checkbox) {
    function ok() {
        doGridClick(selection, item);
    }

    if (item.model.isModified()) {
        showConfirmDialog($("#uncheckScheduleDialog"), function() {
            ok();
            $(this).dialog("close");
        }, function() {
            checkbox.checked = "checked";
            grid.invalidate();
            $(this).dialog("close");
        }, false);
    } else {
        ok();
    }
}

function onPaste(pasteData, grid, dataView) {
    var $table = $("#excelImportTable");
    var $tr, $td;

    $table.children().remove();

    var pos = grid.getCurrentCell();
    var columns = grid.getColumns();
    var gridData = grid.getData();
    var fields = [];

    if (pos && pasteData[0]) {
        $table.append($tr = $("<tr></tr>"));

        $tr.append(
                $("<th></th>").text(columns[0].name),
                $("<th></th>").text(columns[1].name),
                $("<th></th>").text(columns[2].name),
                $("<th></th>").text(columns[3].name),
                $("<th></th>").text(columns[4].name)
        );

        for (var i = 0; i < pasteData[0].length; i++) {
            var header = columns[pos.cell + i];

            $tr.append($td = $("<th></th>"));

            if (header) {
                $td.text(header.name);
                fields[i] = header.field;
            } else {
                $td.addClass("null");
            }
        }
    }

    $.each(pasteData, function(i, row) {
        $table.append($tr = $("<tr></tr>"));

        var dataRow = gridData[pos.row + i];
        var hours = dataRow.parent.getHours();

        if (!dataRow) {
            $tr.addClass("null");
            dataRow = {start: "-", schedule: "-", workspaceDesc: "-", type: "-", uomDesc: "-"};
        }

        $tr.append(
                $("<th></th>").text(dataRow.start),
                $("<th></th>").text(dataRow.schedule),
                $("<th></th>").text(dataRow.workspaceDesc),
                $("<th></th>").text(dataRow.type),
                $("<th></th>").text(dataRow.uomDesc)
        );


        $.each(row, function(j, cell) {
            var column = columns[pos.cell + j];

            $tr.append($td = $("<td></td>"));

            var isCellFillingPossible = (column.hour * DateTime.MILLIS_PER_HOUR + column.minute * DateTime.MILLIS_PER_MINUTE) % dataRow.resolution === 0;

            if (dataRow && column && (hours.indexOf(column.hour) === -1 || (column.extra === true && hours.length == 24)) || !isCellFillingPossible) {
                $td.addClass("null");
            }

            cell != null || cell !== undefined ? $td.text(cell) : $tr.addClass("null");
        });
    });

    showConfirmDialog($("#excelImportDialog"), function() {
        var gridData = grid.getData();
        var cell = grid.getCurrentCell();

        if (cell == null || cell === undefined) {
            alert("Choose the start cell");
        }

        for (var v = 0; v < pasteData.length; v++) {
            if (v + cell.row < gridData.length) {
                for (var w = 0; w < pasteData[v].length; w++) {
                    var column = columns[cell.cell + w];
                    var item = gridData[v + cell.row];
                    var hours = item.parent.getHours();

                    var isCellFillingPossible = (column.hour * DateTime.MILLIS_PER_HOUR + column.minute * DateTime.MILLIS_PER_MINUTE) % item.resolution === 0;

                    if (column && !(hours.indexOf(column.hour) === -1 || (column.extra === true && hours.length == 24)) && isCellFillingPossible) {
                        if (item[column.field] === undefined) {
                            item[column.field] = item.parent.model.append(null, item.parent.model.getShift(column.hour, column.minute, column.extra), item.getType());
                        }

                        item[column.field].value(parseFloat(pasteData[v][w]));
                    }
                }
            }
        }

        changeButtonsState();
        dataView.refresh();
        grid.invalidate();

        $(this).dialog("close");
    }, null, false);
}

function validFormInput() {
    var tuple = {
        start : Date.parse($("#startDay").val(), DATE_FORMAT),
        stop : Date.parse($("#stopDay").val(), DATE_FORMAT),
        ws : selectedWorkspaceCode(),
        type : selectedType(),
        ident : selectedIdentification()
    };

    // Duplication records checking
    var valid = true;
    $.each(masterData, function() {
        return (valid = !this.model.isEqual(tuple.start, tuple.stop, tuple.ws, tuple.type, tuple.ident));
    });
    return valid;
}

function isIdentificationEmpty() {
    return $.trim(selectedIdentification()) == '';
}

function newScheduleClick() {
    var start = Date.parse($("#day").val(), "yyyy-MM-dd");
    var stop = start.calendar().plusDays(1).toDate();

    $("#startDay").val(start.toString(DATE_FORMAT));
    $("#stopDay").val(stop.toString(DATE_FORMAT));

    if (selectedScheduleType().breakpoint) {
        $("#isBreakpoint").parent().css("visibility", "visible");
    } else {
        $("#isBreakpoint").parent().css("visibility", "hidden");
        $("#isBreakpoint").removeAttr("checked");
    }

    clearIdentification();
    $("#addScheduleDialog fieldset").find(".dyno").remove();
    $("#addScheduleDialog fieldset").append($(".dyno").clone());
    $("#addScheduleDialog fieldset").find(".dyno").children().each(function() {
        var element = $(this);
        element.attr("id") && element.attr("id", element.attr("id") + "newDialog");
        element.attr("for") && element.attr("for", element.attr("for") + "newDialog");

        if (element.is("select")) {
            element.children("option:first").remove();
            element.change(null);
        }
    });

    showConfirmDialog($("#addScheduleDialog"), function() {
        // OK clicked -- go create new schedule

        if (isIdentificationEmpty()) {
            $("#emptyIdentificationError").show();
            return;
        }

        if (!validFormInput()) {
            $("#addScheduleDialogError").show();
            return;
        }

        var parameters = [];
        var values = [];

        var schedule = {
            id: --sequence,
            version: 0,
            workspace: selectedWorkspaceCode(),
            interval: {start: start, stop: stop},
            identification: selectedIdentification(),
            type: selectedType(),
            documentIdentification: '',
            status: '',
            deleted: false,
            parameters: parameters,
            values: values
        };

        $("#addScheduleDialog").find(".dyno select").each(function() {
            if ($(this).val() !== "") {
                parameters[parameters.length] = {entity: $(this).val(), type: $(this).attr("code")};
            }
        });

        var bp = $("#isBreakpoint").is(":checked");

        selected.put(new ScheduleModel(schedule, bp, dateHours));

        processData([schedule], []/*, breakpointColumns*/);

        masterGrid.data(masterData);

        if (bp) {
            processBreakpoints();
        } else {
            intervalGrid.data(intervalData);
        }

        $("#addScheduleDialog").dialog("close");
    }, null, false, function() {
        // Clean up ...
        $("#addScheduleDialog").find(".dyno").remove();
        $("#addScheduleDialogError").hide();
        $("#emptyIdentificationError").hide();
    });
}

function excelExport() {
    var ids = $.map(masterGrid.dataView.getItems(), function(item) {
        if (item.isSelected()) {
            return item.key();
        }
    });

    if (ids.length > 0) {
        ScheduleServiceRemote.exportToExcel(ids, {callback: function(data) {
                    if (data == null) {
                        alert("Export to excel failed.");
                    } else {
                        dwr.engine.openInDownload(data);
                    }
                }});
    } else {
        showAlertDialog($("#excelReportWarningDialog"), defaultCloseFunction(), 500, 200);
    }
}

function rampExport() {
    var $fieldset = $("#rampReportDialog fieldset");
    var $hidden = $fieldset.children(".hidden");

    selected.list(function() {
        var $clone = $hidden.clone().removeClass("hidden").addClass("dyno").attr("key", this.key());

        $clone.children(".description").text(this.schedule().identification);

        var rampUnit = {};

        rampUnit = $.map(this.getValueTypes(),
                function(item) {
                    return item.unit.code + "/h";
                });

        $clone.children(".rampUnit").text(rampUnit.join(','));

        $clone.children(".align").change(
                function () {
                    var $this = $(this);
                    var $fluxion = $this.parent().children(".fluxion");

                    if ($this.val() == "NONE" || $this.val() == "LINEAR") {
                        if ($fluxion.hasClass("error")) {
                            $fluxion.removeClass("error");
                            $fluxion.addClass("errorHidden");
                        }

                        $fluxion.attr("disabled", "disabled");
                    } else {
                        if ($fluxion.hasClass("errorHidden")) {
                            $fluxion.addClass("error");
                            $fluxion.removeClass("errorHidden");
                        }

                        $fluxion.removeAttr("disabled");
                    }
                }).change();

        if (this.isBreakpoint()) {
            $clone.children(".align").attr("disabled", "disabled");
        }

        $fieldset.append($clone);
    });

    $fieldset.find(".fluxion").keyup(function() {
        var $this = $(this);
        var val = $this.val();

        if ($.trim(val) == '' || isNaN(val)) {
            $this.addClass("error");
        } else {
            $this.removeClass("error");
            $this.removeClass("errorHidden");
        }
    });

    $("#rampReportDialog").append($fieldset);

    showConfirmDialog($("#rampReportDialog"), function() {
        checkEmptyRateFields();

        if ($fieldset.find(".fluxion.error").length !== 0) {
            return;
        }

        var ids = $("#rampReportDialog fieldset div.dyno").map(
                function() {
                    var $this = $(this);
                    var $fluxion = $this.children(".fluxion");

                    return {
                        scheduleId: $this.attr("key"),
                        align: $this.children(".align").val(),
                        fluxion: $fluxion.attr("disabled") !== undefined ? 0 : $fluxion.val()
                    };
                }).toArray();

        if (ids.length > 0) {
            ScheduleServiceRemote.exportToPdf(ids, {callback: function(data) {
                        if (data == null) {
                            alert("Export to PDF failed.");
                        } else {
                            dwr.engine.openInDownload(data);
                        }
                    }});
        } else {
            showAlertDialog($("#excelReportWarningDialog"), defaultCloseFunction(), 500, 200);
        }
    }, null, false, function() {
        $("#rampReportDialog fieldset .dyno").remove();
    });

}
/**
 * Checks whether text fields are empty
 */
function checkEmptyRateFields() {
    $("#rampReportDialog fieldset div.dyno").each(function() {
        var $elem = $(this).children(".fluxion");

        if ($elem.attr("disabled") === undefined && $.trim($elem.val()) == '') {
            $elem.addClass("error");
        }
    });
}

function addPoint() {
    showConfirmDialog($("#addPointDialog"), function() {
        var time = $("#addPointTime").timeEntry("getTime");

        var columns = {};
        var colKey = detailColumn(columns, time.getHours(), time.getMinutes(), false);

        var column = columns[colKey];

        column.breakpoint = true;

        $.each(breakpointColumns, function() {
            if (this.id === colKey) {
                colKey = null;
                return false;
            }
        });

        if (colKey == null) {
            $("#addPointError").show();

            return;
        }

        breakpointColumns[breakpointColumns.length] = columns[colKey];

        breakpointColumns.sort(compareColumns);

        breakpointGrid.data(breakpointData).columns([].concat(detailColumns).concat(breakpointColumns));

        $(this).dialog("close");
    }, null, false);
}

function identity(e) {
    return e;
}

function selectedType() {
    return $("#scheduleType").val();
}

function selectedScheduleType() {
    return scheduleTypes[selectedType()];
}

/**
 * @param {string} code
 * @return {schedule|undefined}
 */
function scheduleTypeByCode(code) {
    return scheduleTypes[code];
}

/**
 * Can edit schedule or not.
 *
 * It is not possible to edit a schedule that
 * is bound to non-editable schedule type. But
 * you can edit any schedule that belongs to
 * study workspace.
 *
 * @param {schedule} schedule
 * @return {boolean} can edit schedule or not
 */
function canEditSchedule(schedule) {
    if (scheduleTypeByCode(schedule.type).editable) {
        return true;
    } else {
        // ... but can edit when study w.s.
        // or can't in case of master w.s.
        return schedule.workspace != null;
    }
}

/**
 * Exist any filtered schedules in the grid or not
 */
function gotTheShownSchedules() {
    for (var i = 0; i < masterData.length; i++) {
        if (masterFilter(masterData[i])) {
            return true;
        }
    }

    return false;
}

/**
 * @return {?string} selected workspace code
 */
function selectedWorkspaceCode() {
    return $("#workspace").val() === "" ? null : $("#workspace").val();
}

/**
 * @param {string}
        */
function selectedIdentification() {
    return $("#scheduleIdentification").val();
}

/**
 * clear identification UI field
 */
function clearIdentification() {
    $("#scheduleIdentification").val('');
}

function DecimalCellFormatter(row, cell, value, columnDef, dataContext) {
    if (value === undefined || value === null || value.isEmpty()) {
        return "";
    }

    var roundedValue = parseFloat(value.value().toFixed((-1) * dataContext._unit.exponent));

    if (value.isNew()) {
        return "<span class='value new-value'>" + roundedValue + "</span>";
    }

    if (value.isModified()) {
        return "<span class='value changed-value'>" + roundedValue + "</span>";
    }

    return "<span class='value unchanged-value'>" + roundedValue + "</span>";
}


